﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO;
using SuperQuiz.Model;
using System.Collections.Generic;
using System.IO.IsolatedStorage;
using System.Globalization;
using System.Text;

namespace SuperQuiz.Parser
{
    public class Parser
    {
        #region Parser

        //private StreamReader readFile = null;
        private States state = States.Init;

        enum States { Init, Ready, WatingQuestion, Term, SimpleQuestion, RelatedQuestion };
        enum Symbol { Definition, Commentary, Empty, EOF, SimpleText, Assertion, FalseAssertion, Alternative, RightAlternative, Unknow, First, Second }
        private string first = "";
        private string lastfirst = null;
        private AssociativeQuestion associativeQuestion;
        private int associateQuestionCount;
        private Question newSimpleQuestion;
        private string questionTitle;
        private string currentDefinition;

        public Dictionary<string, Test> Tests = new Dictionary<string, Test>();

        private Symbol GetSymbol(String line)
        {

            if (line == null)
                return Symbol.EOF;

            line = line.Trim();

            if (line.StartsWith("#"))
                return Symbol.Commentary;

            if (line.StartsWith("@"))
                return Symbol.Definition;

            if (line.StartsWith(">"))
                return Symbol.First;

            if (line.StartsWith("=>"))
                return Symbol.Second;

            if (line == String.Empty)
                return Symbol.Empty;

            if (line.EndsWith("!"))
                return Symbol.Assertion;

            if (line.EndsWith("~"))
                return Symbol.FalseAssertion;

            if (line.StartsWith("-"))
                return Symbol.Alternative;

            if (line.StartsWith("*"))
                return Symbol.RightAlternative;


            if (line.Trim().Length > 0)
                return Symbol.SimpleText;

            return Symbol.Unknow;
        }


        private void Feed(String line)
        {
            Symbol symbol = GetSymbol(line);

            if (symbol == Symbol.Commentary) return;
            //if (symbol == Symbol.Empty) return;

            if (state == States.Init)
            {
                switch (symbol)
                {
                    case Symbol.Definition:
                        SetDefinition(line);
                        state = States.Ready;
                        break;
                    case Symbol.Empty:
                        break;
                    default:
                        throw new Exception("");
                }

            }
            else if (state == States.Ready)
            {
                switch (symbol)
                {
                    case Symbol.Definition:
                        SetDefinition(line);
                        state = States.Ready;
                        break;
                    case Symbol.Empty:
                        //state = States.Init;
                        break;
                    case Symbol.EOF:
                        state = States.Term;
                        break;
                    case Symbol.SimpleText:
                        state = States.WatingQuestion;
                        SetSimpleQuestion(line);
                        break;
                    case Symbol.Assertion:
                        SetAssertion(line);
                        break;
                    case Symbol.FalseAssertion:
                        SetFalseAssertion(line);
                        break;
                    default:
                        throw new Exception("");
                }
            }
            else if (state == States.WatingQuestion)
            {
                switch (symbol)
                {
                    case Symbol.Empty:
                    case Symbol.EOF:
                        //SaveSimpleQuestion();
                        //state = States.Ready;
                        state = States.SimpleQuestion;
                        break;
                    case Symbol.Alternative:
                        AddSimpleQuestion(questionTitle);
                        AddAlternative(line, false);
                        state = States.SimpleQuestion;
                        break;
                    case Symbol.RightAlternative:
                        AddSimpleQuestion(questionTitle);
                        AddAlternative(line, true);
                        state = States.SimpleQuestion;
                        break;
                    case Symbol.First:
                        AddRelatedQuestion(questionTitle);
                        AddFirst(line, false);
                        state = States.RelatedQuestion;
                        break;
                    default:
                        throw new Exception("");
                }
            }
            else if (state == States.SimpleQuestion)
            {
                switch (symbol)
                {
                    case Symbol.Empty:
                    case Symbol.EOF:
                        SaveSimpleQuestion();
                        state = States.Ready;
                        break;
                    case Symbol.Alternative:
                        AddAlternative(line, false);
                        break;
                    case Symbol.RightAlternative:
                        AddAlternative(line, true);
                        break;
                    default:
                        throw new Exception("");
                }
            }
            else if (state == States.RelatedQuestion)
            {
                switch (symbol)
                {
                    case Symbol.Empty:
                    case Symbol.EOF:
                        SaveRelatedQuestion();
                        state = States.Ready;
                        break;
                    case Symbol.First:
                        AddFirst(line, false);
                        state = States.RelatedQuestion;
                        break;
                    case Symbol.Second:
                        AddSecond(line, false);
                        state = States.RelatedQuestion;
                        break;
                    default:
                        throw new Exception("");
                }
            }
            else
            {
                throw new Exception("");
            }
        }

        private void AddSecond(string line, bool p)
        {
            CheckFirst();
            line = line.Trim();
            line = line.Substring(2);
            associativeQuestion.Second.Add(new AssociativeItem(line, associateQuestionCount));
        }

        private void CheckFirst()
        {
            if (lastfirst != first)
            {
                associativeQuestion.First.Add(first);
                lastfirst = first;
                associateQuestionCount++;
            }
        }



        private void AddFirst(string line, bool p)
        {
            line = line.Trim();
            line = line.Substring(1);
            first = line;
        }

        private void SaveRelatedQuestion()
        {
            

            foreach (AssociativeItem item in associativeQuestion.Second)
            {
                Question myQuestion = new Question();

                myQuestion.Text = item.Text;
                myQuestion.MyAlternatives = new List<Alternative>();
                int i = 1;
                foreach (string s in associativeQuestion.First)
                {
                    
                    Boolean value;
                    if ( item.Value == i)
                        value = true ;
                    else
                        value = false;
                    myQuestion.MyAlternatives.Add( new Alternative( s, value));
                    i++;
                }
                AddNewQuestion(this.currentDefinition, myQuestion);
            }
        }



        private void AddRelatedQuestion(string questionTitle)
        {
            associateQuestionCount = 0;
            associativeQuestion = new AssociativeQuestion();
            associativeQuestion.Text = questionTitle;
            associativeQuestion.First = new List<string>();
            associativeQuestion.Second = new List<AssociativeItem>();
        }

        private void AddSimpleQuestion(string questionTitle)
        {
            newSimpleQuestion = new Question();
            newSimpleQuestion.Text = questionTitle;
            newSimpleQuestion.MyAlternatives = new List<Alternative>();

        }

        #endregion



        private void SaveSimpleQuestion()
        {
            AddNewQuestion(currentDefinition, newSimpleQuestion);
        }

        private void AddAlternative(string line, bool p)
        {
            line = line.Trim();
            line = line.Substring(1);
            newSimpleQuestion.MyAlternatives.Add(new Alternative(line, p));

            Console.WriteLine("xxxx");
        }

        private void SetAssertion(string line)
        {
            Question question = new Question();
            question = MyFactory.CreateQuestion(line.Substring(0, line.Length - 1), 1, "Certo", "Errado");
            AddNewQuestion(currentDefinition, question);
            Console.WriteLine("xxxx");
        }

        private void SetFalseAssertion(string line)
        {
            Question question = new Question();
            question = MyFactory.CreateQuestion(line.Substring(0, line.Length - 1), 2, "Certo", "Errado");
            AddNewQuestion(currentDefinition, question);
            Console.WriteLine("xxxx");
        }

        private void AddNewQuestion(string currentDefinition, Question question)
        {

            if (Tests.ContainsKey(currentDefinition))
            {
                Tests[currentDefinition].Questions.Add(question);
            }
            else
            {
                Test newTest = new Test(currentDefinition);
                newTest.Questions.Add(question);
                Tests[currentDefinition] = newTest;
            }

        }


        private void SetSimpleQuestion(string line)
        {
            questionTitle = line;
        }

        private void SetDefinition(string line)
        {

            currentDefinition = line.Trim().Substring(1);
            Console.WriteLine("xxxx");
        }


        public Parser(Uri uri)
        {
            Stream ResourceInfo = App.GetResourceStream(uri).Stream;

            ParseStream(ResourceInfo);
        }


        public Parser(Stream ResourceInfo)
        {
            ParseStream(ResourceInfo);
        }

        private static Encoding GetEncoding()
        {
            CultureInfo cultureInfo = new CultureInfo("pt-BR");
            Encoding encoding = Encoding.GetEncoding("ISO-8859-1");
            return encoding;
        }



        public Parser(string fileName)
        {
            using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
            using (IsolatedStorageFileStream file = store.OpenFile(fileName, FileMode.Open))
            {
                ParseStream(file);
            }
        }

        private void ParseStream(Stream stream)
        {
            Encoding encoding = GetEncoding();
            StreamReader readFile = new StreamReader(stream, encoding);
            String line;
            line = readFile.ReadLine();
            while (!readFile.EndOfStream)
            {
                Feed(line);
                line = readFile.ReadLine();

            } Feed(null);
            string fileText = readFile.ReadLine();
            readFile.Close();
        }
    }
}
